#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "color.h"

int sdl_error()
{
	printf("SDL error %s\n", SDL_GetError());
	return 1;
}

int sdl_print_bpp()
{
	const SDL_VideoInfo* vi;
	const SDL_PixelFormat* pf;
	vi = SDL_GetVideoInfo();
	if(!vi)
		sdl_error();
	pf = vi->vfmt;
	printf("we need bpp 32, check what we have\n");
	printf("bpp %d\n", pf->BitsPerPixel);
	return 1;
}

int sdl_preset_opengl()
{
	if(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8))
		sdl_error();
    if(SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8))
    	sdl_error();
    if(SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8))
    	sdl_error();
    if(SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16))
    	sdl_error();
    if(SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1))
    	sdl_error();
    return 1;
}

int sdl_create_window()
{
	if(SDL_Init(SDL_INIT_VIDEO))
		sdl_error();
	sdl_print_bpp();
	sdl_preset_opengl();
    if (!SDL_SetVideoMode(800, 600, 32, SDL_OPENGL 
		| SDL_NOFRAME))
    	sdl_error();
	return 1;
}

int gl_print_error()
{
    GLenum error;
    error = glGetError();
    if (error == GL_NO_ERROR) {
        return 0;
    }
    printf("%s", glGetString(error));
    return 1;
}

const int Wait_Clear = 1;
const int Wait_Normal = 2;

int wait(int mode) 
{
    // 16 milisecs per frame
    const float stable_frame = 1000 / 60; 
    const int hard_step = 10;
    static float start_time = 0;
    static float speed_up = 0;
    float frame_time;
    float delay, free_time, end_time;
    int sleep_time;
    
    if(mode == Wait_Clear)
    {
        start_time = SDL_GetTicks();
        speed_up = 0;
        return 0;
    }
    
    if(start_time == 0)
        start_time = SDL_GetTicks();
    end_time = SDL_GetTicks();    
    frame_time = end_time - start_time;
    start_time = end_time;
    if(frame_time == stable_frame)
        return 1;
    // if frame time is slower saving speedup value
    if(frame_time > stable_frame) {
        speed_up += frame_time - stable_frame;
        return 1; 
    }
    // if frame time is quicker we wait by 10 milisecs
    if(frame_time < stable_frame) {
        free_time = stable_frame - frame_time;
        // lowering the tail
        speed_up -= free_time;
        // if we just shorted the gap
        if(speed_up >= 0)
            return 1;
        // if we need to slow
        delay = -speed_up;
        if(delay < hard_step)
            // we can not sleep such short time
            return 1;
        sleep_time = ((int)delay / (int)hard_step) *
            (int)hard_step;
        //sleep_time = hard_step;
        SDL_Delay(sleep_time);
        speed_up += sleep_time;
        start_time += sleep_time;
    }
    return 1;
}

int print_fps()
{
    static Uint32 last_time = 0;
    static Uint32 frame_count = 0;
    static Uint32 frame_time = 0;
    Uint32 time, delta_time;
    int fps;
    char buffer[64];
    
    if(last_time == 0)
        last_time = SDL_GetTicks();
    time = SDL_GetTicks();
    delta_time = time - last_time;
    last_time = time;
    frame_count++;
    frame_time+=delta_time;
    if(frame_time >= 1000) {
        fps = frame_count;
        if((fps > 55) && (fps < 65)) {
            sprintf(buffer, "COLOR");
        } else {
            sprintf(buffer, "COLOR fps %d\n", fps);
        }
        printf("%d ", fps);
        //SDL_WM_SetCaption(buffer, 0);
        frame_count = 0;
        frame_time -= 1000;
    }
    return 1;
}

int gl_init()
{	
    load_table(); 
    make_marks();
    make_color_range(13, colors);
    make_slice_color_range(13, colors, 100, 255);
    
	glClearDepth(1.0f);
	glDepthFunc(GL_LESS);               
    glEnable(GL_DEPTH_TEST); 
	glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
	glColor3f(1.0f, 0.0f, 0.0f);
	glShadeModel(GL_SMOOTH);                     
	glViewport(0, 0, 800, 600);
	glMatrixMode(GL_PROJECTION); 
	glOrtho(-400, 400, -300, 300, -1000, 1000);
    //gluPerspective(45.0f, (float)800/(float)600,  
        // 0.1f, 100.0f);                           
    glMatrixMode(GL_MODELVIEW);
	return 1;   
}

int init()
{
	sdl_create_window();
	gl_init();
	return 1;
}

int draw()
{
     // eye x y z, center x y z, up x y z
	 gluLookAt(0, 0, 1,  0, 0, 0,  0, 1, 0);
	 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	 glLoadIdentity();
	 glTranslatef(0.0f, 0.0f, -3.0f);
	 
	 SDL_GL_SwapBuffers();
	 gl_print_error();
	 wait(Wait_Normal);
	 print_fps();
	 return 1;
}

int process_events()
{
	SDL_Event event;
	while(SDL_PollEvent(&event))
	{
		switch(event.type) 
    	{
    		// exit on escape
    		case SDL_KEYDOWN:
    			if(event.key.keysym.sym == SDLK_ESCAPE)
    			{
     				SDL_Quit();
     				return 0;
     			}
     			if(event.key.keysym.sym == SDLK_SPACE)
    			{
     				return 1;
     			}
     			break;
     		// exit on window close button
     		case SDL_QUIT:
     			return 0;
    	}
    	
 	}
 	return 1;
}

int main()
{
	init();
	while(process_events()) 
	{
    	if(!draw())
    	   break;
    }
    if(file)
        fclose(file);
	return 0;
}
